<template>
  <div class="current_page">
    <div class="current_page_left">
      <div
        id="container"
        ref="container"
        @mousedown.stop
        @mousemove="handleMouseMove"
        @touchstart.stop
        @touchmove="handleMouseMove"
      ></div>
    </div>
    <div class="current_page_right">
      <MyCanvasOperate
        @updateTopBackColor="updateTopBackColor"
        @updateBottomBackColor="updateBottomBackColor"
        @addTopic="addTopic"
        @addContact="addContact"
      ></MyCanvasOperate>
    </div>
  </div>
</template>

<script>
import { Graph, Path } from '@antv/x6';
// import { Graph, Cell, Node, Path } from '@antv/x6';

import { Keyboard } from '@antv/x6-plugin-keyboard';
import { Selection } from '@antv/x6-plugin-selection';
import Hierarchy from '@antv/hierarchy';
import insertCss from 'insert-css';
import MyCanvasOperate from './myCanvasOperate.vue';
import { cloneDeep } from 'lodash';

// 中心主题或分支主题
Graph.registerNode(
  'topic',
  {
    inherit: 'rect',
    markup: [
      {
        tagName: 'rect',
        selector: 'body',
      },
      {
        tagName: 'image',
        selector: 'img',
      },
      {
        tagName: 'text',
        selector: 'label',
      },
    ],
    attrs: {
      body: {
        rx: 6,
        ry: 6,
        stroke: '#5F95FF',
        fill: '#EFF4FF',
        strokeWidth: 1,
      },
      img: {
        ref: 'body',
        refX: '100%',
        refY: '50%',
        refY2: -8,
        width: 16,
        height: 16,
        'xlink:href': 'https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*SYCuQ6HHs5cAAAAAAAAAAAAAARQnAQ',
        event: 'add:topic',
        class: 'topic-image',
      },
      label: {
        fontSize: 14,
        fill: '#262626',
      },
    },
  },
  true,
);

// 子主题
Graph.registerNode(
  'topic-child',
  {
    inherit: 'rect',
    markup: [
      {
        tagName: 'rect',
        selector: 'body',
      },
      {
        tagName: 'text',
        selector: 'label',
      },
      {
        tagName: 'image',
        selector: 'img',
      },
      // {
      //   tagName: "path",
      //   selector: "line",
      // },
    ],
    attrs: {
      body: {
        fill: '#ffffff',
        strokeWidth: 0,
        stroke: '#5F95FF',
      },
      img: {
        ref: 'body',
        refX: '100%',
        refY: '50%',
        refY2: -8,
        width: 16,
        height: 16,
        'xlink:href': 'https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*SYCuQ6HHs5cAAAAAAAAAAAAAARQnAQ',
        event: 'add:topic',
        class: 'topic-image',
      },
      label: {
        fontSize: 14,
        fill: '#262626',
        // textVerticalAnchor: "center",
      },
      // line: {
      //   stroke: "#5F95FF",
      //   strokeWidth: 3,
      //   d: "M 0 15 L 60 15",
      // },
    },
  },
  true,
);

// 连接器
Graph.registerConnector(
  'mindmap',
  (sourcePoint, targetPoint, routerPoints, options) => {
    const midX = sourcePoint.x + 10;
    const midY = sourcePoint.y;
    const ctrX = (targetPoint.x - midX) / 5 + midX;
    const ctrY = targetPoint.y;
    const pathData = `
     M ${sourcePoint.x} ${sourcePoint.y}
     L ${midX} ${midY}
     Q ${ctrX} ${ctrY} ${targetPoint.x} ${targetPoint.y}
    `;
    return options.raw ? Path.parse(pathData) : pathData;
  },
  true,
);

// 边
Graph.registerEdge(
  'mindmap-edge',
  {
    inherit: 'edge',
    connector: {
      name: 'normal',
    },
    attrs: {
      line: {
        targetMarker: '',
        stroke: '#A2B1C3',
        strokeWidth: 2,
      },
    },
    zIndex: 0,
  },
  true,
);

const _dataSource = {
  id: '1',
  type: 'topic',
  label: '中心主题',
  width: 160,
  height: 50,
  level: 1,

  children: [
    {
      id: '1-1',
      type: 'topic-branch',
      label: '分支主题1',
      width: 100,
      height: 40,
      level: 2,
      children: [
        {
          id: '1-1-1',
          type: 'topic-child',
          label: '子主题1',
          width: 60,
          height: 30,
          level: 3,
        },
        {
          id: '1-1-2',
          type: 'topic-child',
          label: '子主题2',
          width: 60,
          height: 30,
          level: 3,
        },
      ],
    },
    {
      id: '1-2',
      type: 'topic-branch',
      label: '分支主题2',
      width: 100,
      height: 40,
      level: 2,
    },
  ],
};
export default {
  components: { MyCanvasOperate },
  props: {
    dir: String,
  },
  data() {
    return {
      graph: null,
      dataSource: JSON.parse(JSON.stringify(_dataSource)),
      line: null,
      lineStart: null,
      lineArr: [],
      topColor: '#EFF4FF', // 新增分支主题时设置颜色
    };
  },
  watch: {
    dir() {
      this.render();
    },
  },
  mounted() {
    this.graph = new Graph({
      container: this.$refs.container,
      panning: true,
      mousewheel: true,

      connecting: {
        connectionPoint: 'anchor',
      },
      highlighting: {},
      interacting: { nodeMovable: false }, // 节点是否可以被移动。
      // translating: { restrict: true },
      grid: true, // 显示网格
      snapline: true, // 吸附线
    });
    this.graph.use(new Selection());
    this.graph.use(new Keyboard());
    // 点击加号执行
    this.graph.on('add:topic', ({ node }) => {
      const { id } = node;
      const type = node.prop('type');

      if (this.addChildNode(id, type)) {
        this.render();
      }
    });
    this.graph.bindKey(['backspace', 'delete'], (e) => {
      console.log('e =============<> ', e);
      e.stopPropagation();
      e.preventDefault();

      const selectedNodes = this.graph.getSelectedCells().filter((item) => item.isNode());
      if (selectedNodes.length) {
        const { id } = selectedNodes[0];

        if (this.removeNode(id)) {
          this.render();
        }
      }
      // 选中边去删除
      const selectedEdges = this.graph.getSelectedCells().filter((item) => item.isEdge());

      if (selectedEdges.length) {
        this.graph.removeEdge(selectedEdges[0]);
        this.lineArr.splice(
          this.lineArr.findIndex((item) => item.id === selectedEdges[0].id),
          1,
        );
      }
    });
    // 选中节点设置边起始节点
    this.graph.on('node:click', ({ e, node }) => {
      e.stopPropagation();
      this.lineStart = node;
    });
    // 创建线条且handleMouseMove后点击画布任意位置其实是先点击到当前边上的
    // 用这个操作来结束当前边的设计
    this.graph.on('edge:click', () => {
      if (this.lineStart && this.line) {
        // 让线条从节点外面开始发散
        this.render();
        this.lineStart = null;
        this.line = null;
      }
    });

    insertCss(`
    .topic-image {
      visibility: hidden;
      cursor: pointer;
    }
    .x6-node:hover .topic-image {
      visibility: visible;
    }
    .x6-node-selected rect {
      stroke-width: 2px;
    }
  `);
    this.render();
    this.graph.centerContent();
  },
  beforeDestroy() {},
  methods: {
    // 计算字节
    getByteLength(str) {
      let byteLength = 0;
      for (let i = 0; i < str.length; i++) {
        const charCode = str.charCodeAt(i);
        if (charCode <= 0x007f) {
          // 英文字符或数字，字节数为1
          byteLength += 1;
        } else if (charCode <= 0x07ff) {
          // 拉丁文扩展等，字节数为2
          byteLength += 2;
        } else if (charCode >= 0x4e00 && charCode <= 0x9fff) {
          // 中日韩统一表意文字，字节数为3
          byteLength += 3;
        } else {
          // 其他字符，假设字节数为3
          byteLength += 3;
        }
      }
      return byteLength;
    },
    updateWidthById(data, id, newWidth) {
      // 如果当前节点的 id 符合要求，修改宽度
      if (data.id === id) {
        data.width = newWidth;
      }

      // 如果当前节点有子节点，递归处理每个子节点
      if (data.children && data.children.length > 0) {
        data.children.forEach((child) => {
          this.updateWidthById(child, id, newWidth); // 递归调用
        });
      }

      return data;
    },
    render() {
      console.log(111);
      let that = this;
      console.log('this.dataSource ======================> ', JSON.stringify(this.dataSource));
      const result = Hierarchy.mindmap(this.dataSource, {
        direction: 'H',
        getHeight: (d) =>
          // console.log(this.dataSource, 'dddd', this.dir);
          // return d.height;
          this.dir === 'H' ? d.height : d.width,
        getWidth: (d) =>
          // return d.width;
          this.dir === 'H' ? d.width : d.height,
        getHGap() {
          return 20;
        },
        getVGap() {
          return 20;
        },
        getSide: () => 'right',
      });
      const cells = [];
      const traverse = (hierarchyItem) => {
        if (hierarchyItem) {
          const { data, children } = hierarchyItem;

          cells.push(
            this.graph.createNode({
              id: data.id,
              shape: data.type === 'topic-child' ? 'topic-child' : 'topic',
              // x: hierarchyItem.x,
              // y: hierarchyItem.y,
              x: this.dir === 'H' ? hierarchyItem.x : hierarchyItem.y,
              y: this.dir === 'H' ? hierarchyItem.y : hierarchyItem.x,
              width: data.width,
              height: data.height,
              label: data.label,

              attrs: {
                body: {
                  rx: 6,
                  ry: 6,
                  stroke: '#5F95FF',
                  fill: data.type === 'topic-child' ? data.backGroundColor || 'white' : data.backGroundColor,
                  strokeWidth: 1,
                },
              },
              type: data.type,

              tools: {
                name: 'node-editor',
                args: {
                  attrs: {
                    backgroundColor: '#FFF',
                  },
                  setText({ cell, value }) {
                    // 修改后，重新执行render 根据 cell.id
                    // console.log(this.dataSource);
                    cell.attr('text/text', value);
                    data.label = value;
                    // 根据文本字节长度设置宽度
                    const byteLength = that.getByteLength(value);
                    const averageCharWidth = 5; // 每个字符的平均宽度（可以根据实际情况调整）
                    const padding = 10; // 单元格左右内边距（可以根据实际情况调整）
                    let newWidth = byteLength * averageCharWidth + padding;
                    // 设置单元格的宽度
                    const deep = cloneDeep(that.dataSource);
                    if (!value) {
                      console.log('一样的');
                      return;
                    }
                    // 如果为1级节点, 且宽度小于默认值160，就设置为默认宽度
                    if (cell.id.length == 1 && newWidth < 160) {
                      newWidth = 160;
                    }
                    // 如果为1-1二级节点, 且宽度小于默认值100，就设置为默认宽度
                    if (cell.id.split('-').length == 2 && newWidth < 100) {
                      newWidth = 100;
                    }

                    that.updateWidthById(deep, cell.id, newWidth);
                    that.dataSource = deep;
                    // 重新渲染
                    that.render();
                  },
                },
              },
            }),
          );
          if (children) {
            children.forEach((item) => {
              const { id, data } = item;
              cells.push(
                this.graph.createEdge({
                  shape: 'mindmap-edge',
                  source: {
                    cell: hierarchyItem.id,
                    anchor:
                      data.type === 'topic-child'
                        ? {
                            name: 'center',
                            // args: {
                            //   dx: -16,
                            // },
                          }
                        : {
                            name: 'center',
                            // args: {
                            //   dx: "25%",
                            // },
                          },
                  },
                  target: {
                    cell: id,
                    // anchor: {
                    //   name: "left",
                    // },
                  },
                }),
              );
              traverse(item);
            });
          }
        }
      };
      traverse(result);

      this.graph.resetCells(cells);
      this.lineArr.forEach((item) => {
        this.graph.addEdge(item);
      });
      // this.graph.center();
      // this.graph.positionContent('left')
      // 画完线后会重新render。继而centerContent会让图形移位
      // this.graph.centerContent();
    },
    findItem(obj, id) {
      if (obj.id === id) {
        return {
          parent: null,
          node: obj,
        };
      }
      const { children } = obj;
      if (children) {
        for (let i = 0, len = children.length; i < len; i += 1) {
          const res = this.findItem(children[i], id);
          if (res) {
            return {
              parent: res.parent || obj,
              node: res.node,
            };
          }
        }
      }
      return null;
    },
    replaceObjectById(obj, newObj) {
      if (obj.id === newObj.id) {
        // 如果当前对象的id和新对象的id相同，则替换当前对象
        Object.assign(obj, newObj);
      } else if (obj.children) {
        // 如果有子节点，则对每个子节点进行递归调用
        obj.children.forEach((child) => this.replaceObjectById(child, newObj));
      }
    },

    removeNode(id) {
      const res = this.findItem(this.dataSource, id);
      const dataItem = res?.parent;
      if (dataItem && dataItem.children) {
        const { children } = dataItem;
        const index = children.findIndex((item) => item.id === id);
        this.replaceObjectById(this.dataSource, dataItem);
        // updateMaping(this.dataSource);
        return children.splice(index, 1);
      }
      return null;
    },
    replaceObject(obj, color) {
      if (obj.id) {
        // 如果当前对象的id和新对象的id相同，则替换当前对象
        obj.type !== 'topic-child' ? (obj.backGroundColor = color) : '';
      }
      if (obj.children?.length) {
        // 如果有子节点，则对每个子节点进行递归调用
        obj.children.forEach((child) => {
          this.replaceObject(child, color);
        });
      }
    },
    addChildNode(id, type) {
      const res = this.findItem(this.dataSource, id);
      const dataItem = res?.node;

      if (dataItem) {
        let item = null;
        const length = dataItem.children ? dataItem.children.length : 0;
        if (type === 'topic') {
          item = {
            id: `${id}-${length + 1}`,
            type: 'topic-branch',
            label: `分支主题${length + 1}`,
            width: 100,
            height: 40,
            backGroundColor: this.topColor ? this.topColor : '',
          };
        } else if (type === 'topic-branch') {
          item = {
            id: `${id}-${length + 1}`,
            type: 'topic-child',
            label: `子主题${length + 1}`,
            width: 60,
            height: 30,
          };
        } else if (type === 'topic-child') {
          item = {
            id: `${id}-${length + 1}`,
            type: 'topic-child',
            label: `子主题${length + 1}`,
            width: 60,
            height: 30,
          };
        }
        if (item) {
          if (dataItem.children) {
            dataItem.children.push(item);
          } else {
            dataItem.children = [item];
          }
          this.replaceObjectById(this.dataSource, dataItem);
          // updateMaping(this.dataSource);
          return item;
        }
      }
      return null;
    },
    addSameNode(id, type) {
      // 顶级节点
      if (type === 'topic') {
        this.$message({
          type: 'warning',
          message: '此节点不能添加同级节点',
          showClose: true,
          duration: 2000,
        });
        return;
      }

      const res = this.findItem(this.dataSource, id);
      const dataItem = res?.parent;

      if (dataItem) {
        let item = null;
        const length = dataItem.children ? dataItem.children.length : 0;
        if (dataItem.type === 'topic') {
          item = {
            id: `${dataItem.id}-${length + 1}`,
            type: 'topic-branch',
            label: `分支主题${length + 1}`,
            width: 100,
            height: 40,
            backGroundColor: this.topColor ? this.topColor : '',
          };
        } else if (dataItem.type === 'topic-branch') {
          item = {
            id: `${dataItem.id}-${length + 1}`,
            type: 'topic-child',
            label: `子主题${length + 1}`,
            width: 60,
            height: 30,
          };
        } else if (dataItem.type === 'topic-child') {
          item = {
            id: `${dataItem.id}-${length + 1}`,
            type: 'topic-child',
            label: `子主题${length + 1}`,
            width: 60,
            height: 30,
          };
        }

        if (item) {
          if (dataItem.children) {
            dataItem.children.push(item);
          } else {
            dataItem.children = [item];
          }
          this.replaceObjectById(this.dataSource, dataItem);

          return item;
        }
      }
      return null;
    },
    addTopNode(id, type) {
      // 顶级节点与第二节点不参与
      if (type === 'topic' || type === 'topic-branch') {
        this.$message({
          type: 'warning',
          message: '此节点不能向上添加节点',
          showClose: true,
          duration: 2000,
        });
        return;
      }

      const res = this.findItem(this.dataSource, id);
      const dataItem = res?.parent;
      const resTop = this.findItem(this.dataSource, dataItem.id);
      const dataItemTop = resTop?.parent;

      if (dataItemTop) {
        let item = null;
        const length = dataItemTop.children ? dataItemTop.children.length : 0;
        if (dataItemTop.type === 'topic') {
          item = {
            id: `${dataItemTop.id}-${length + 1}`,
            type: 'topic-branch',
            label: `分支主题${length + 1}`,
            width: 100,
            height: 40,
            backGroundColor: this.topColor ? this.topColor : '',
          };
        } else if (dataItemTop.type === 'topic-branch') {
          item = {
            id: `${dataItemTop.id}-${length + 1}`,
            type: 'topic-child',
            label: `子主题${length + 1}`,
            width: 60,
            height: 30,
          };
        }
        if (item) {
          if (dataItemTop.children) {
            dataItemTop.children.push(item);
          } else {
            dataItemTop.children = [item];
          }
          this.replaceObjectById(this.dataSource, dataItemTop);

          return item;
        }
      }
      return null;
    },
    addNodeBasedOnTopicTier(topicTier, nodeId, type) {
      if (topicTier === 'sam') {
        return this.addSameNode(nodeId, type);
      }
      if (topicTier === 'top') {
        return this.addTopNode(nodeId, type);
      }
      if (topicTier === 'bot') {
        return this.addChildNode(nodeId, type);
      }
      // Handle other cases if needed
      return false;
    },
    updateTopBackColor(color) {
      // const selectedNodes = this.graph
      //   .getSelectedCells()
      //   .filter((item) => item.isNode());
      // if (selectedNodes.length) {
      this.topColor = color;
      this.replaceObject(this.dataSource, color);
      this.render();
      // }
    },
    updateBottomBackColor(color) {
      const selectedNodes = this.graph.getSelectedCells().filter((item) => item.isNode());
      if (selectedNodes.length) {
        const node = selectedNodes[0];
        const res = this.findItem(this.dataSource, node.id);
        res.node.backGroundColor = color;
        this.render();
      } else {
        this.$message({
          type: 'warning',
          message: '请选择节点',
          showClose: true,
          duration: 2000,
        });
      }
    },
    addTopic(topicTier) {
      const selectedNodes = this.graph.getSelectedCells().filter((item) => item.isNode());
      if (selectedNodes.length) {
        const node = selectedNodes[0];

        const type = node.prop('type');

        if (this.addNodeBasedOnTopicTier(topicTier, node.id, type)) {
          this.render();
        }
      } else {
        this.$message({
          type: 'warning',
          message: '请选择节点',
          showClose: true,
          duration: 2000,
        });
      }
    },
    addContact() {
      const selectedNodes = this.graph.getSelectedCells().filter((item) => item.isNode());
      if (selectedNodes.length) {
        const node = selectedNodes[0];

        // const type = node.prop('type');
        if (node && !this.line) {
          const localMousePos = this.graph.clientToLocal({
            x: window.clientX,
            y: window.clientY,
          });
          console.log(localMousePos);
          // 创建一条线
          this.createLine(localMousePos);
        }
      } else {
        this.$message({
          type: 'warning',
          message: '请选择节点',
          showClose: true,
          duration: 2000,
        });
      }
      // this.render();
    },
    createLine(endPosition) {
      // 从起始节点到终点位置创建一条线
      if (!this.graph) return;
      if (this.lineStart) {
        console.log(this.lineStart);
        this.line = this.graph.addEdge({
          source: {
            cell: this.lineStart,
            port: 'source', // 表示源节点的边缘端口
          },
          target: endPosition,
          // vertices: [{ x: 1, y: 1 }],
          connector: { name: 'smooth' },
          attrs: {
            line: {
              stroke: '#1890ff',
              strokeDasharray: 5,
              targetMarker: 'classic',
            },
          },
          labels: [
            {
              attrs: {
                line: {
                  stroke: '#73d13d',
                },
                text: {
                  text: '联系',
                },
              },
            },
          ],
        });

        this.lineArr.push(this.line);
      }
    },
    handleMouseMove(event) {
      if (this.lineStart && this.line) {
        const localMousePos = this.graph.clientToLocal({
          x: event.pageX,
          y: event.pageY,
        });

        // 更新线的终点为当前鼠标位置
        this.updateLineEndpoint(localMousePos);
      }
    },
    updateLineEndpoint(endPosition) {
      // 更新线的终点位置
      this.line.setTarget(endPosition);
    },
  },
};
</script>
<style lang="scss" scoped>
.current_page {
  flex: 1;
  height: 100%;
  display: flex;
  padding: 10px;

  .current_page_left {
    width: 70%;
    height: 32rem;
    padding-right: 20px;
    box-sizing: border-box;

    #container {
      width: 100%;
      height: 100%;
      // text-align: none;
    }
  }
  .current_page_right {
    // margin-left: 20px;
    flex: 1;
    // border: 1px solid red;
  }
}
</style>
